﻿export interface ICallback<ArgType>
{
    (arg: ArgType, context?: any);
}

export interface ICallbackDesc<ArgType>
{
    Callback: ICallback<ArgType>;
    Subscriber: any;
}

export class Event<ArgType>
{
    private Callbacks: ICallbackDesc<ArgType>[] = [];

    /** Подписаться на событие
    * @param {ICallback<ArgType>} callback Callback, который будет вызван при вызове функции
    * @param {any} subscriber Контекст, в котором должен быть вызван callback
    * @returns {ITypedSubscription<ArgType>} Объект типизированной подписки
    */
    public Subscribe(callback: ICallback<ArgType>, subscriber: any): ITypedSubscription<ArgType>
    { 
        var that = this;

        var res: ITypedSubscription<ArgType> =
        {
            Callback: callback,
            Event: that,
            Unsubscribe: function () { that.Unsubscribe(callback); }
        }

        this.Callbacks.push({ Callback: callback, Subscriber: subscriber });

        return res;
    }

    public Unsubscribe(callback: ICallback<ArgType>): void 
    { 
        var filteredList: ICallbackDesc<ArgType>[] = [];

        for (var i = 0; i < this.Callbacks.length; i++)
        {
            if (this.Callbacks[i].Callback !== callback)
            {
                filteredList.push(this.Callbacks[i]);                
            }
        }

        this.Callbacks = filteredList;
    }

    public Trigger: ICallback<ArgType> = function (arg: ArgType, context?: any)
    {
        var callbacks: ICallbackDesc<ArgType>[] = this.Callbacks;
        for (var i = 0; i < callbacks.length; i++)
        {
            callbacks[i].Callback.apply(callbacks[i].Subscriber, [arg, context]);
        }
    }
}

/** Базовый интерфейс подписки на событие. Минимальная функциональность. Можем просто отписаться и все. */
export interface ISubscription
{
    Unsubscribe: { (): void };
}

/** Типизированная версия. Включает ссылки на событие и callback */
export interface ITypedSubscription<ArgType> extends ISubscription
{
    Callback: ICallback<ArgType>;
    Event: Event<ArgType>;
}
